//
// Created by YimingCai on 25/03/2017.
//

#include <stddef.h>
//Definition for singly-linked list.
struct ListNode {
      int val;
      ListNode *next;
      ListNode(int x) : val(x), next(NULL) {}
 };

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int isCarried = 0;
        ListNode *ret = nullptr;
        ListNode **tailp = &ret;
        while (l1 && l2) {
            int sum = l1->val + l2->val + isCarried;
            isCarried = sum / 10;
            sum %= 10;
            *tailp = new ListNode(sum);
            tailp = &((*tailp)->next);
            l1 = l1->next;
            l2 = l2->next;
        }
        if (l1 || l2) {
            ListNode *l = l1 ? l1 : l2;
            while (l) {
                int sum = l->val + isCarried;
                *tailp = new ListNode(sum % 10);
                isCarried = sum / 10;
                tailp = &((*tailp)->next);
                l = l->next;
            }
        }
        if (isCarried) {
            *tailp = new ListNode(isCarried);
        }
        return ret;
    }
};



#include <gtest/gtest.h>

class AddTwoNumbersTest : public testing::Test {
protected:
    ListNode *AddTwoList(ListNode *l1, ListNode *l2) {
        l_ = Solution().addTwoNumbers(l1, l2);
        return l_;
    }
    void ExpectSize(int s) {
        ListNode *l = l_;
        int len = 0;
        while (l) {
            len++;
            l = l->next;
        }
        ASSERT_EQ(s, len);
    }
    void ExpectIdxVal(int idx, int val) {
        EXPECT_EQ(val, this->listNum(l_, idx));
    }
    static ListNode* createList(int count, ...)
    {
        va_list args;
        va_start(args, count);
        ListNode *ret = NULL;
        ListNode **tailp = &ret;
        for (int i = 0; i < count; ++i)
        {
            int arg = va_arg(args, int);
            *tailp = new ListNode(arg);
            tailp = &((*tailp)->next);
        }
        va_end(args);
        return ret;
    }
protected:
    virtual void SetUp() {
        l1_ = nullptr;
        l2_ = nullptr;
        l_ = nullptr;
    }
    virtual void TearDown() {
        if (l1_) this->freeList(l1_);
        if (l2_) this->freeList(l2_);
        if (l_) this->freeList(l_);
    }

private:

    static void freeList(ListNode *l)
    {
        while (l) {
            ListNode *n = l->next;
            delete l;
            l = n;
        }
    }
    static int listNum(ListNode *l, int idx)
    {
        while(idx > 0) {
            l = l->next;
            idx--;
        }
        return l->val;
    }

    ListNode *l1_, *l2_, *l_;
};


TEST_F(AddTwoNumbersTest, test1) {
    AddTwoList(this->createList(4, 9, 9, 9, 9), this->createList(2, 9, 9));
    ExpectSize(5);
    ExpectIdxVal(0, 8);
    ExpectIdxVal(1, 9);
    ExpectIdxVal(2, 0);
    ExpectIdxVal(3, 0);
    ExpectIdxVal(4, 1);
}

TEST_F(AddTwoNumbersTest, test2) {
    AddTwoList(this->createList(3, 2, 4, 3), this->createList(3, 5, 6, 4));
    ExpectSize(3);
    ExpectIdxVal(0, 7);
    ExpectIdxVal(1, 0);
    ExpectIdxVal(2, 8);
}

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    int ret = RUN_ALL_TESTS();
    return ret;
}
